/*
  List: a templated class for a doubly-linked list.

  Jason Hood. Public domain.
  28 to 30 November, 1997.
*/

#include "list.h"


/* -----------------------------   Copy c'tor   -----------------------------

  The update flag is copied from the list, and as such, this list will either
  point to the first item (updating is false), or the last (updating is true).

*/

template <class Type>
List<Type>::List(const List<Type>& list) : current(&base), items(0),
					   update_cur(list.update_cur)
{
  for (Node<Type>* cur = list.base.next; cur != &list.base; cur = cur->next)
    append(cur->item);
}


/* -----------------------------   Assignment	-----------------------------

  Make this list the same as another, except for the update flag. Re-use items
  already allocated, then remove or append items as necessary. The current
  pointer will be at the first item.

*/

template <class Type>
List<Type>& List<Type>::operator=(const List<Type>& list)
{
  if (list.items == 0) empty();
  else
  {
    long copy = (items <= list.items) ? items : list.items;
    Node<Type>* cur = list.base.next;
    current = base.next;
    for (; copy > 0; --copy)
    {
      current->item = cur->item;
      current	    = current->next;
      cur	    = cur->next;
    }
    copy = items - list.items;
    if (copy < 0)			// The new list is bigger
    {
      while (cur != &list.base)
      {
	append(cur->item);
	cur = cur->next;
      }
    }
    else				// The new list is smaller
    {
      for (; copy > 0; --copy) remove();
    }
    current = base.next;
  }
  return *this;
}


/* -------------------------------   insert   -------------------------------

  Insert a new item into the list, either before or after the here node and
  return a pointer to it. If the item could not be created, return 0.

  If this is the first item, or update_cur is true, point current to it.

*/

template <class Type>
Type* List<Type>::insert(const Type& item, Node<Type>* here, bool before)
{
  Node<Type>* node = new Node<Type>(item);
  if (node == 0) return 0;

  if (before)
  {
    node->next	     = here;
    node->prev	     = here->prev;
    here->prev	     =
    here->prev->next = node;
  }
  else
  {
    node->prev	     = here;
    node->next	     = here->next;
    here->next	     =
    here->next->prev = node;
  }
  ++items;
  if (update_cur || items == 1) current = node;

  return *node;
}


/* -------------------------------   remove   -------------------------------

  Remove an item from the list, provided there's an item to be removed. If it's
  the current item, point it to the next item, otherwise the current pointer
  remains unchanged.

*/

template <class Type>
void List<Type>::remove(Node<Type>* node)
{
  if (node == 0 || items == 0) return;
  node->prev->next = node->next;
  node->next->prev = node->prev;
  if (current == node) current = node->next;
  delete node;
  --items;
}


/* -------------------------------   empty   --------------------------------

  Free all memory occupied by the list, and get it ready to start a new one.

*/

template <class Type>
void List<Type>::empty()
{
  if (items == 0) return;

  Node<Type>* del;
  current = base.next;
  do
  {
    del     = current;
    current = current->next;
    delete del;
  }
  while (current != &base);

  base.next = base.prev = &base;
  items = 0;
}


#ifdef TEST_LIST

#include <stdio.h>

typedef List<int> intList;
typedef Node<int> intNode;

int main()
{
  intList ints;
  intNode* node;

  ints.append(1);
  ints.append(3); node = ints;
  ints.append(5);

  ints.move(node); ints.update(false);
  ints.insert(2, true); ints.insert(4);

  foritems (int, ints) printf("%d ", *item);
  putchar('\n');

  return 0;
}

#endif
